﻿jQuery.iFisheye = {
    build: function (options) {

        return this.each(
			function () {
			    var el = this;
			    el.fisheyeCfg = {
			        items: jQuery(options.items, this),
			        container: jQuery(options.container, this),
			        pos: jQuery.iUtil.getPosition(this),
			        itemWidth: options.itemWidth,
			        itemsText: options.itemsText,
			        proximity: options.proximity,
			        valign: options.valign,
			        halign: options.halign,
			        maxWidth: options.maxWidth,
			        dropMenuSelector: options.dropMenu,
			        dropMenuItemSelector: options.dropMenuItem,
			        dropMenus: jQuery(options.dropMenu, this),
			        dropMenuRadius: options.dropMenuRadius,
			        radiusDirection: options.radiusDirection,
			        duration: ((options.duration && options.duration > 0) ? options.duration : 500),
			        delay: ((options.delay && options.delay > 0) ? options.delay : 500),
			        onmenuclick: options.onmenuclick,
			        moveup: options.moveup,
			        movedown: options.movedown,
			        popupWidth: options.popupWidth,
			        maxMenuItemCount: options.maxMenuItemCount ? options.maxMenuItemCount : 6,
			        popupHoverBorder: options.popupHoverBorder ? options.popupHoverBorder : 'none',
			        shownMenu: null,
			        animate_tid: [],
			        mouseover_tid: [],
			        mouseout_tid: [],
			        menuHeights: []
			    };
			    el.fisheyeCfg.radiusDirection = el.fisheyeCfg.radiusDirection ? el.fisheyeCfg.radiusDirection : 'right';
			    el.fisheyeCfg.delay = el.fisheyeCfg.delay == 0 ? el.fisheyeCfg.duration : el.fisheyeCfg.delay;
			    jQuery.iFisheye.positionContainer(el, 0);
			    jQuery(window).bind(
					'resize',
					function () {
					    el.fisheyeCfg.pos = jQuery.iUtil.getPosition(el);
					    jQuery.iFisheye.positionContainer(el, 0);
					    jQuery.iFisheye.positionItems(el);
					}
				);
			    jQuery.iFisheye.positionItems(el);
			    el.fisheyeCfg.items
                    .each(function (index) {
                        jQuery(this).hover(
                                function (e) {
                                    if (jQuery(el.fisheyeCfg.dropMenuItemSelector, this).size() <= 0) {
                                        jQuery(el.fisheyeCfg.itemsText, this).css('display', 'block');
                                    }
                                    if (el.fisheyeCfg.mouseout_tid[index]) {
                                        clearTimeout(el.fisheyeCfg.mouseout_tid[index]);
                                    }
                                    el.fisheyeCfg.mouseover_tid[index] = setTimeout(
                                        function () {
                                            jQuery.iFisheye.animateMenuItems1(el, index, 'show');
                                        }
                                        , el.fisheyeCfg.delay
                                    );
                                    return false;
                                },
                                function (e) {
                                    jQuery(el.fisheyeCfg.itemsText, this).css('display', 'none');
                                    if (el.fisheyeCfg.mouseover_tid[index]) {
                                        clearTimeout(el.fisheyeCfg.mouseover_tid[index]);
                                    }
                                    el.fisheyeCfg.mouseout_tid[index] = setTimeout(
                                        function () {
                                            jQuery.iFisheye.animateMenuItems1(el, index, 'hide');
                                        }
                                        , el.fisheyeCfg.delay
                                    );
                                    return false;
                                }
                            );
                    });
			    if (el.fisheyeCfg.onmenuclick) {
			        el.fisheyeCfg.items.click(function (e) { el.fisheyeCfg.onmenuclick(e); });
			    }
			    el.fisheyeCfg.dropMenus
                    .hover(
                        function (e) {
                            el.fisheyeCfg.shownMenu = this;
                        },
                        function (e) {
                            el.fisheyeCfg.shownMenu = null;
                        }
                    );
			    jQuery(document)
                    .mousemove(
					    function (e) {
					        e = e || window.event;
					        var target = e.srcElement || e.target;
					        var pointer = jQuery.iUtil.getPointer(e);
					        var toAdd = 0;
					        if (el.fisheyeCfg.halign && el.fisheyeCfg.halign == 'center')
					            var posx = pointer.x - el.fisheyeCfg.pos.x - (el.offsetWidth - el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size()) / 2 - el.fisheyeCfg.itemWidth / 2;
					        else if (el.fisheyeCfg.halign && el.fisheyeCfg.halign == 'right')
					            var posx = pointer.x - el.fisheyeCfg.pos.x - el.offsetWidth + el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size();
					        else
					            var posx = pointer.x - el.fisheyeCfg.pos.x;
					        var posy = Math.pow(pointer.y - el.fisheyeCfg.pos.y - el.offsetHeight / 2, 2);
					        if (el.fisheyeCfg.shownMenu && jQuery(el.fisheyeCfg.shownMenu).css('display') == 'block') {
					            //posy = 0;
					        }
					        //var posy = Math.pow(pointer.y - el.fisheyeCfg.pos.y, 2);
					        el.fisheyeCfg.items.each(
							    function (nr) {
							        distance = Math.sqrt(
									    Math.pow(posx - nr * el.fisheyeCfg.itemWidth, 2)
									    + posy
								    );
							        distance -= el.fisheyeCfg.itemWidth / 2;

							        distance = distance < 0 ? 0 : distance;
							        distance = distance > el.fisheyeCfg.proximity ? el.fisheyeCfg.proximity : distance;
							        distance = el.fisheyeCfg.proximity - distance;

							        extraWidth = el.fisheyeCfg.maxWidth * distance / el.fisheyeCfg.proximity;

							        this.style.width = el.fisheyeCfg.itemWidth + extraWidth + 'px';
							        this.style.left = el.fisheyeCfg.itemWidth * nr + toAdd + 'px';
							        toAdd += extraWidth;
							    }
						    );
					        jQuery.iFisheye.positionContainer(el, toAdd);
					    }
				);
			}
		)
    },

    positionContainer: function (el, toAdd) {
        if (el.fisheyeCfg.halign)
            if (el.fisheyeCfg.halign == 'center')
                el.fisheyeCfg.container.get(0).style.left = (el.offsetWidth - el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size()) / 2 - toAdd / 2 + 'px';
            else if (el.fisheyeCfg.halign == 'left')
                el.fisheyeCfg.container.get(0).style.left = -toAdd / el.fisheyeCfg.items.size() + 'px';
            else if (el.fisheyeCfg.halign == 'right')
                el.fisheyeCfg.container.get(0).style.left = (el.offsetWidth - el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size()) - toAdd / 2 + 'px';
        el.fisheyeCfg.container.get(0).style.width = el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size() + toAdd + 'px';
    },

    positionItems: function (el) {
        el.fisheyeCfg.items.each(
			function (nr) {
			    this.style.width = el.fisheyeCfg.itemWidth + 'px';
			    this.style.left = el.fisheyeCfg.itemWidth * nr + 'px';
			}
		);
    },
    animateMenuItems: function (el, index, displayType) {
        var totalTime = el.fisheyeCfg.duration;
        var interval = 1;
        var count = totalTime / interval;
        var dock = jQuery(el.fisheyeCfg.items.get(index));
        var menuItems = jQuery(el.fisheyeCfg.dropMenuItemSelector, dock);
        var itemCount = menuItems.size();
        var radius = el.fisheyeCfg.dropMenuRadius;
        var ind = 0;
        var isShow = (displayType && displayType == 'show');
        var radiusDirection = (el.fisheyeCfg.radiusDirection && el.fisheyeCfg.radiusDirection == 'right') ? 1 : -1;
        var vlignDirection = (el.fisheyeCfg.radiusDirection && el.fisheyeCfg.valign == 'bottom') ? -1 : 1;

        clearInterval(el.fisheyeCfg.animate_tid[index]);
        if (menuItems.size() <= 0) {
            if (isShow) {
                jQuery(el.fisheyeCfg.itemsText, dock).show();
            }
            else {
                jQuery(el.fisheyeCfg.itemsText, dock).hide();
            }
        }
        else {
            el.fisheyeCfg.animate_tid[index] = setInterval(
                function () {
                    ind++;
                    var rotateCount = isShow ? ind : (count - ind);
                    var dockItem = jQuery(el.fisheyeCfg.items.get(index)).children('a').children('img');
                    var dockItemWidth = dockItem.width();
                    var dockItemHeight = dockItem.height();
                    var dockItemPosition = dockItem.position();
                    var rotateHeight = itemCount * dockItem.height() * rotateCount / count;
                    var height = isShow ? rotateHeight : Math.min(rotateHeight, el.fisheyeCfg.menuHeights[index]);
                    el.fisheyeCfg.menuHeights[index] = height;
                    for (var i = menuItems.size() - 1; i >= 0; i--) {
                        var rotateMenuItem = jQuery(menuItems.get(i));
                        rotateMenuItem.children('a').height(dockItemHeight + 'px');
                        if (height > 0) {
                            rotateMenuItem.css('display', 'block').css('z-index', -100).width(dockItemWidth + 'px').height(dockItemHeight + 'px');
                            var centerY = height - dockItemHeight / 2;
                            centerY = centerY > 0 ? centerY : 0;
                            var top = (vlignDirection > 0 ? (dockItemPosition.top + height - dockItemHeight) : (dockItemPosition.top - height));
                            rotateMenuItem.css('top', top + 'px')
                                          .css('left', radiusDirection * (radius - Math.sqrt(Math.pow(radius, 2) - Math.pow(height, 2))) + 'px')
                            height = height - dockItemWidth;
                            var itemText = rotateMenuItem.children('span');
                            var itemTextWidth = itemText.width();
                            itemText.height(dockItemHeight).css(el.fisheyeCfg.radiusDirection, dockItemWidth + 'px').css('line-height', dockItemHeight + 'px')
                            .css('text-align', el.fisheyeCfg.radiusDirection);
                        }
                        else {
                            jQuery(menuItems.get(i)).css('display', 'none');
                        }
                    }
                    if (ind >= count) {
                        clearInterval(el.fisheyeCfg.animate_tid[index]);
                    }
                }
                , interval
                );
        }
    },
    animateMenuItems1: function (el, index, displayType) {
        var maxCount = el.fisheyeCfg.maxMenuItemCount;
        var totalTime = el.fisheyeCfg.duration;
        var interval = 1;
        var count = totalTime / interval;
        var dock = jQuery(el.fisheyeCfg.items.get(index));
        var menuItems = jQuery(el.fisheyeCfg.dropMenuItemSelector, dock);
        var itemSize = menuItems.not(el.fisheyeCfg.moveup).not(el.fisheyeCfg.movedown).size();
        var itemCount = Math.min(itemSize, maxCount);
        var showMouveUp = el.fisheyeCfg.moveup && (itemSize > maxCount);
        itemCount = showMouveUp ? (itemCount) : itemCount;
        var radius = el.fisheyeCfg.dropMenuRadius;
        var ind = 0;
        var isShow = (displayType && displayType == 'show');
        var radiusDirection = (el.fisheyeCfg.radiusDirection && el.fisheyeCfg.radiusDirection == 'right') ? 1 : -1;
        var vlignDirection = (el.fisheyeCfg.radiusDirection && el.fisheyeCfg.valign == 'bottom') ? -1 : 1;

        $(el.fisheyeCfg.moveup, dock).unbind('click');
        $(el.fisheyeCfg.movedown, dock).unbind('click');

        clearInterval(el.fisheyeCfg.animate_tid[index]);
        if (menuItems.size() <= 0) {
            if (isShow) {
                jQuery(el.fisheyeCfg.itemsText, dock).css('display', 'block');
            }
            else {
                jQuery(el.fisheyeCfg.itemsText, dock).css('display', 'none');
            }
        }
        else {
            el.fisheyeCfg.animate_tid[index] = setInterval(
                function () {
                    ind++;
                    var rotateCount = isShow ? ind : (count - ind);
                    var dockItem = jQuery(el.fisheyeCfg.items.get(index)).children('a').children('img');
                    var dockItemWidth = el.fisheyeCfg.popupWidth ? el.fisheyeCfg.popupWidth : 0.8 * dockItem.width();
                    var dockItemHeight = el.fisheyeCfg.popupWidth ? el.fisheyeCfg.popupWidth : 0.8 * dockItem.height();
                    var dockItemPosition = dockItem.position();
                    var rotateHeight = itemCount * dockItemHeight * rotateCount / count;
                    var height = isShow ? rotateHeight : Math.min(rotateHeight, el.fisheyeCfg.menuHeights[index]);
                    el.fisheyeCfg.menuHeights[index] = height;
                    var hasShownItems = 0;
                    for (var i = menuItems.size() - 1; i >= 0; i--) {
                        var rotateMenuItem = jQuery(menuItems.get(i));
                        if (rotateMenuItem.hasClass(el.fisheyeCfg.moveup.substr(1)) || rotateMenuItem.hasClass(el.fisheyeCfg.movedown.substr(1))) {
                            if (showMouveUp) {
                                rotateMenuItem.css('display', 'block');
                            }
                            else {
                                continue;
                            }
                        }
                        rotateMenuItem.children('a').height(dockItemHeight + 'px');
                        rotateMenuItem.children('a').children('img')
                        //                                      .css('opacity', '0.8')
                                       .hover(
                                        function () { $(this).width(dockItemWidth * 1.2).css('border', el.fisheyeCfg.popupHoverBorder); },
                                        function () { $(this).width(dockItemWidth).css('border', 'none'); }
                                        );
                        var itemShouldShown = false;
                        if (showMouveUp) {
                            if (hasShownItems >= 0 && hasShownItems <= maxCount - 2) {
                                itemShouldShown = true;
                            }
                            else {
                                if (rotateMenuItem.hasClass(el.fisheyeCfg.moveup.substr(1)) || rotateMenuItem.hasClass(el.fisheyeCfg.movedown.substr(1))) {
                                    itemShouldShown = true;
                                }
                            }
                        }
                        else {
                            if (hasShownItems >= 0 && hasShownItems < maxCount) {
                                itemShouldShown = true;
                            }
                        }
                        if (height > 0 && itemShouldShown) {
                            rotateMenuItem.css('display', 'block').css('z-index', 100).width(dockItemWidth + 'px').height(dockItemHeight + 'px');
                            var centerY = height - dockItemHeight / 2;
                            centerY = centerY > 0 ? centerY : 0;
                            var top = (vlignDirection > 0 ? (dockItemPosition.top + height - dockItemHeight) : (dockItemPosition.top - height));
                            rotateMenuItem.css('top', top + 'px')
                                          .css('left', radiusDirection * (radius - Math.sqrt(Math.pow(radius, 2) - Math.pow(height, 2))) + 'px')
                            height = height - dockItemWidth;
                            var itemText = rotateMenuItem.children('span');
                            var itemTextWidth = itemText.width();
                            itemText.height(dockItemHeight).css(el.fisheyeCfg.radiusDirection, dockItemWidth + 'px').css('line-height', dockItemHeight + 'px')
                            .css('text-align', el.fisheyeCfg.radiusDirection).css('z-index', 100);
                            hasShownItems++;
                        }
                        else {
                            rotateMenuItem.css('display', 'none');
                        }
                    }
                    if (ind >= count) {
                        clearInterval(el.fisheyeCfg.animate_tid[index]);
                        if (el.fisheyeCfg.moveup) {
                            if (isShow) {
                                $(el.fisheyeCfg.moveup, dock).bind('click', function () {
                                    jQuery.iFisheye.moveMenuItems(el, index, menuItems, 'up');
                                });

                                $(el.fisheyeCfg.movedown, dock).bind('click', function () {
                                    jQuery.iFisheye.moveMenuItems(el, index, menuItems, 'down');
                                });
                            }
                            else {
                                $(el.fisheyeCfg.moveup, dock).unbind('click');
                                $(el.fisheyeCfg.movedown, dock).unbind('click');
                            }
                        }
                    }
                }
                , interval
                );
        }
    },
    moveMenuItems: function (el, index, menuItems, direction) {
        direction = direction || 'up';
        var moveDirection = direction == 'up' ? 1 : -1;
        var maxShowCount = el.fisheyeCfg.maxMenuItemCount;
        var totolSize = menuItems.size();
        var menuItemCount = menuItems.not(el.fisheyeCfg.moveup).size();
        var hasHideFromEnd = 0;
        var hasHideFromStart = 0;
        var needMove = false;

        var dockImg = jQuery(el.fisheyeCfg.items.get(index)).children('a').children('img');
        var dockImgPosition = dockImg.position();
        var moveUpMenuItem = jQuery(menuItems.filter(el.fisheyeCfg.moveup));
        var moveUpMenuItemPosition = moveUpMenuItem.position();
        var comparedPosition = moveDirection > 0 ? dockImgPosition : moveUpMenuItemPosition;

        var from = moveDirection > 0 ? (totolSize - 1) : 0;
        var to = moveDirection < 0 ? (totolSize - 1) : 0;
        var constraint = function (ii) { return moveDirection > 0 ? ii >= to : ii <= to; }

        // move up menuitem is always the last one.
        for (var i = from; constraint(i); i = i - moveDirection) {
            var menuItem = jQuery(menuItems.get(i));
            if (menuItem.hasClass(el.fisheyeCfg.moveup.substr(1)) || menuItem.hasClass(el.fisheyeCfg.movedown.substr(1))) {
                continue;
            }
            if (menuItem.css('display') != 'block') {
                hasHideFromEnd++;
                continue;
            }
            var mayShowCount = menuItemCount - hasHideFromEnd;
            if (mayShowCount > maxShowCount - 1) {
                needMove = true;
                break;
            }
        }

        if (needMove) {
            var radiusDirection = (el.fisheyeCfg.radiusDirection && el.fisheyeCfg.radiusDirection == 'right') ? 1 : -1;
            var vlignDirection = (el.fisheyeCfg.radiusDirection && el.fisheyeCfg.valign == 'bottom') ? -1 : 1;

            var duration = parseInt(el.fisheyeCfg.duration / maxShowCount);
          
            var interval = 1;
            var totalIntervalCount = parseInt(duration / interval);
            var currentIndex = 0;
            var radius = el.fisheyeCfg.dropMenuRadius;
            clearInterval(el.fisheyeCfg.animate_tid[index]);
            el.fisheyeCfg.animate_tid[index] = setInterval(function () {
                currentIndex++;
                hasHideFromEnd = 0;
                var hasMovedCount = 0;
                var menuItemHeight = el.fisheyeCfg.popupWidth ? el.fisheyeCfg.popupWidth : moveUpMenuItem.height();
                var menuItemWidth = el.fisheyeCfg.popupWidth ? el.fisheyeCfg.popupWidth : moveUpMenuItem.width();
                for (var i = from; constraint(i); i = i - moveDirection) {
                    var menuItem = jQuery(menuItems.get(i));
                    if (menuItem.hasClass(el.fisheyeCfg.moveup.substr(1)) || menuItem.hasClass(el.fisheyeCfg.movedown.substr(1))) {
                        menuItem.css('z-index', 1000);
                        continue;
                    }
                    if (menuItem.css('display') != 'block' && hasMovedCount == 0) {
                        hasHideFromEnd++;
                        continue;
                    }
                    if (hasMovedCount <= maxShowCount - 2) {
                        if (menuItem.css('display') == 'block') {
                            var height = menuItem.height();
                            var oldTop = parseInt(menuItem.css('top'));
                            var oldLeft = parseInt(menuItem.css('left'));
                            var topDis = moveDirection * vlignDirection * height / totalIntervalCount;
                            var leftDis = moveDirection * radiusDirection * Math.abs(Math.sqrt(Math.pow(radius, 2) - Math.pow(comparedPosition.top - oldTop, 2)) - Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.abs(comparedPosition.top - oldTop) + topDis, 2)));
                            var left = radiusDirection * (radius - Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.abs(dockImg.top - oldTop) + topDis, 2))) + 'px';
                            var relativeHeight = (moveDirection > 0 ? (maxShowCount - hasMovedCount - 1) : (hasMovedCount + 2)) * height + moveDirection * height * currentIndex / totalIntervalCount;
                            var top = (vlignDirection > 0 ? (dockImgPosition.top + relativeHeight - dockItemHeight) : (dockImgPosition.top - relativeHeight));
                            menuItem.css('top', top + 'px')
                                    .css('left', radiusDirection * (radius - Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.abs(dockImgPosition.top - oldTop) + topDis, 2))) + 'px')

                        }
                        else {
                            menuItem.children('a').height(menuItemHeight + 'px');
                            menuItem.css('display', 'block').css('z-index', 100).width(menuItemWidth + 'px').height(menuItemHeight + 'px');

                            var height = menuItem.height();
                            var moveHeight = moveDirection * currentIndex * height / totalIntervalCount;
                            var centerY = moveHeight - menuItemHeight / 2;
                            centerY = centerY > 0 ? centerY : 0;
                            var top = (vlignDirection > 0 ? (comparedPosition.top + moveHeight - menuItemHeight) : (comparedPosition.top - moveHeight));
                            //var left = comparedPosition.left + moveDirection * radiusDirection * (radius - Math.sqrt(Math.pow(radius, 2) - Math.pow(moveHeight, 2)));
                            var leftDis = moveDirection * radiusDirection * Math.abs(Math.sqrt(Math.pow(radius, 2) - Math.pow(comparedPosition.top, 2)) - Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.abs(comparedPosition.top) + topDis, 2)));
                            var left = comparedPosition.left + leftDis;
                            menuItem.css('top', top + 'px').css('left', left + 'px')

                            var itemText = menuItem.children('span');
                            var itemTextWidth = itemText.width();
                            itemText.height(menuItemHeight).css(el.fisheyeCfg.radiusDirection, menuItemWidth + 'px').css('line-height', menuItemHeight + 'px')
                                .css('text-align', el.fisheyeCfg.radiusDirection).css('z-index', 100);
                        }
                        hasMovedCount++;
                    }
                    else {
                        break;
                    }
                }
                if (currentIndex >= totalIntervalCount) {
                    clearInterval(el.fisheyeCfg.animate_tid[index]);
                    for (var i = from; constraint(i); i = i - moveDirection) {
                        var menuItem = jQuery(menuItems.get(i));
                        if (menuItem.hasClass(el.fisheyeCfg.moveup.substr(1)) || menuItem.hasClass(el.fisheyeCfg.movedown.substr(1))) {
                            continue;
                        }
                        if (menuItem.css('display') != 'block') {
                            continue;
                        }
                        menuItem.css('display', 'none');
                        break;
                    }
                }
            }, interval);
        }
    }
};

jQuery.fn.Fisheye = jQuery.iFisheye.build;